﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TagBasedResourceManagePlatform.Database
{
    public class DatabaseInstance
    {
        public enum DatabaseType
        {
            //Default
            Sqlite = 1,
            MySql = 2,
            SqlServer = 3
        }

        public DatabaseType Type { get { return DatabaseType.Sqlite; } }
        private DatabaseContext _context;
        private ThumbnailDB _thumbnails;
        
        public DatabaseContext GetContext()
        {
            return _context;
        }

        public ThumbnailDB GetThumbnailDB()
        {
            return _thumbnails;
        }

        public DatabaseInstance(string configuration = "")
        {
            _context = new DatabaseContext();
        }


        #region Fast Access Functions

        public bool GetMatchResult(string[] tags, out Database.Resource[] result)
        {
            var dbContext = Framework.GetInstance().Database.GetContext();

            try
            {
                string commandText = null;
                StringBuilder sb = new StringBuilder();
                for(int i = 0; i < tags.Length; i++)
                {
                    sb.AppendFormat("{0} ", tags[i]);
                }
                sb.Remove(sb.Length - 1, 1);
                commandText = string.Format("Select [ResourceId] From MAIN.[ResourceTags] WHERE ResourceTags.[Tags] match \"{0}\"", sb.ToString());
                
                var ids = dbContext.Database.SqlQuery<int>(commandText).ToArray();

                if (ids.Length == 0)
                {
                    result = new Resource[0];
                    return true;
                }
                var resources = from TResource in dbContext.Resources where ids.Contains(TResource.Id) select TResource;

                result = resources.ToArray();
                return true;

            }
            catch (Exception ex)
            {
                //TODO: Log this exception.
                result = null;
                return false;
            }
        }
        /*
        public bool CreateFileResourceWithoutThumbnail(string path, string title, string description, string tags)
        {
            System.IO.FileInfo file = new System.IO.FileInfo(path);

            var mineType = Misc.MineTypeHelper.GetMineType(path);
            string md5 = Misc.MD5GenerateHelper.Generate(path);
            string tagsFixed = Misc.Misc.StandardizeTags(tags);

            Resource resource = new Resource()
            {
                AccessLevel = AccessLevel.Any,
                AddTime = DateTime.Now,
                Description = description,
                MD5 = md5,
                MineType = mineType,
                PhysicalPath = path,
                Tags = tagsFixed,
                Title = title,
                Type = ResourceType.File
            };

            ResourceTag tag = new ResourceTag()
            {
                Resource = resource,
                Tags = tagsFixed
            };

            var dbContext = Framework.GetInstance().Database.GetContext();
            dbContext.Resources.Add(resource);
            dbContext.ResourceTags.Add(tag);

            dbContext.SaveChanges();

            return true;
        }
        */
        /*
        public bool CreateFileResourceWithThumbnailData(string path, string title, string description, string tags, System.IO.Stream thumbnailData)
        {
            System.IO.FileInfo file = new System.IO.FileInfo(path);

            var mineType = Misc.MineTypeHelper.GetMineType(path);
            string md5 = Misc.MD5GenerateHelper.Generate(path);
            string tagsFixed = Misc.Misc.StandardizeTags(tags);
            bool hasThumbnail = false;
            string thumbnailFilePath;

            Resource resource = new Resource()
            {
                AccessLevel = AccessLevel.Any,
                CreateTime = DateTime.Now,
                Description = description,
                MD5 = md5,
                MineType = mineType,
                PhysicalPath = path,
                Tags = tagsFixed,
                Title = title,
                Type = ResourceType.File,
            };

            ResourceTag tag = new ResourceTag()
            {
                Resource = resource,
                Tags = tagsFixed
            };

            Thumbnail thumbnail = null;


            System.IO.Stream thumbnailDataStream = thumbnailData;

            if (hasThumbnail)
            {
                thumbnailFilePath = Framework.GetInstance().Configuration.GetNextThumbnailFilePath();

                using (System.IO.FileStream thumbnailFile = System.IO.File.Create(thumbnailFilePath))
                {
                    thumbnailDataStream.Seek(0, System.IO.SeekOrigin.Begin);
                    thumbnailDataStream.CopyTo(thumbnailFile);
                    thumbnailFile.Close();
                }

                thumbnail = new Thumbnail()
                {
                    Path = thumbnailFilePath,
                    Resource = resource,
                    Title = "(index)"
                };
            }

            var dbContext = Framework.GetInstance().Database.GetContext();
            dbContext.Resources.Add(resource);
            dbContext.ResourceTags.Add(tag);
            if (hasThumbnail)
                dbContext.Thumbnails.Add(thumbnail);

            dbContext.SaveChanges();

            return true;
        }
        */
        public bool CreateFileResource(string path,string title, string description, string tags)
        {
            System.IO.FileInfo file = new System.IO.FileInfo(path);

            var mineType = Misc.MineTypeHelper.GetMineType(path);
            string md5 = Misc.MD5GenerateHelper.Generate(path);
            string tagsFixed = Misc.Misc.StandardizeTags(tags);
            bool hasThumbnail = false;

            Resource resource = new Resource()
            {
                AccessLevel = AccessLevel.Any,
                CreateTime = DateTime.Now,
                Description = description,
                MD5 = md5,
                MineType = mineType,
                PhysicalPath = path,
                Tags = tagsFixed,
                Title = title,
                Type = ResourceType.File
            };

            ResourceTag tag = new ResourceTag()
            {
                Resource = resource,
                Tags = tagsFixed
            };

            Thumbnail thumbnail = null;

            System.IO.MemoryStream thumbnailDataStream = new System.IO.MemoryStream();

            hasThumbnail = Misc.ThumbnailHelper.Generate(path, thumbnailDataStream, Misc.ThumbnailHelper.PreferThumbnailSize);
            if (hasThumbnail)
            {
                thumbnail = new Thumbnail()
                {
                    Format = "image/jpeg",
                    Data = thumbnailDataStream.GetBuffer()
                };
            }

            
            if (hasThumbnail)
            {
                try
                {
                    _thumbnails.Thumbnails.Add(thumbnail);
                    _thumbnails.SaveChanges();
                }
                catch
                {
                    hasThumbnail = false;
                }
            }

            if (hasThumbnail) resource.ThumbnailId = thumbnail.Id;
            _context.Resources.Add(resource);
            _context.ResourceTags.Add(tag);
            _context.SaveChanges();

            return true;
        }

        public string GetSettingValue(string name)
        {
            var dbContext = Framework.GetInstance().Database.GetContext();

            var setting = (from TSetting in dbContext.Settings where TSetting.Name == name select TSetting).FirstOrDefault();

            return setting == null ? null : setting.Value;
        }

        public string GetSettingValue(string name, string defaultValue)
        {
            var dbContext = Framework.GetInstance().Database.GetContext();

            var setting = (from TSetting in dbContext.Settings where TSetting.Name == name select TSetting).FirstOrDefault();

            if (setting == null)
            {
                setting = new Setting()
                {
                    Name = name,
                    Value = defaultValue
                };

                dbContext.Settings.Add(setting);
                dbContext.SaveChanges();

                return defaultValue;
            }
            else
            {
                return setting.Value;
            }
        }

        public void SetSettingValue(string name,string value)
        {
            var dbContext = Framework.GetInstance().Database.GetContext();

            var setting = (from TSetting in dbContext.Settings where TSetting.Name == name select TSetting).FirstOrDefault();

            if (setting != null)
            {
                setting.Value = value;
                dbContext.SaveChanges();
            }else
            {
                setting = new Setting()
                {
                    Name = name,
                    Value = value
                };

                dbContext.Settings.Add(setting);
                dbContext.SaveChanges();
            }
        }

        #endregion
    }
}
